package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //本质是创建 OrderInfoVo对象并赋值返回!
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //计算相关金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");
        //  订单明细与减免明细
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        //通过itemType 判读购买类型
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())) {
            //专辑
            //1.查看用户是否购买过专辑
            //远程调用
            Result<Boolean> result = userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(result, "查询用户购买专辑失败");
            if (result.getData()) {
                //用户已经购买过专辑
                throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }
            //未购买专辑
            Result<AlbumInfo> infoVoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(infoVoResult, "查询专辑信息失败");
            AlbumInfo albumInfo = infoVoResult.getData();
            Assert.notNull(albumInfo, "查询专辑信息失败");
            //获取专辑原价
            originalAmount = albumInfo.getPrice();
            //远程调用获取用户信息
            Result<UserInfoVo> userInfoResult = userInfoFeignClient.getUserInfo(userId);
            Assert.notNull(userInfoResult, "查询用户信息失败");
            UserInfoVo userInfoVo = userInfoResult.getData();
            Assert.notNull(userInfoVo, "查询用户信息失败");
            //.判断用户是vip 还是普通用户
            if (userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                //打折 排除-1 这种情况
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1")) != 0) {
                    //计算减免价格
                    //  有折扣; 1000 8 800; 200; 1000*(10-8)/10;
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount()))
                            .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }
            } else {
                //普通用户
                if (albumInfo.getDiscount().compareTo(new BigDecimal("-1")) != 0) {
                    //计算减免价格
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount()))
                            .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }
                //实际价格
                orderAmount = originalAmount.subtract(derateAmount);
                //计算订单明细表
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                //赋值
                orderDetailVo.setItemId(albumInfo.getId());
                orderDetailVo.setItemName(albumInfo.getAlbumTitle());
                orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
                orderDetailVo.setItemPrice(orderAmount);
                orderDetailVoList.add(orderDetailVo);
                //添加减免明细
                if (derateAmount.compareTo(new BigDecimal("0.00")) == 1) {
                    OrderDerateVo orderDerateVo = new OrderDerateVo();
                    orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                    orderDerateVo.setDerateAmount(derateAmount);
                    orderDerateVo.setRemarks("专辑折扣");
                    orderDerateVoList.add(orderDerateVo);
                }


            }
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())) {
            //声音
            if (tradeVo.getTrackCount() < 0) {
                throw new GuiguException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            //如果是0就是购买本身,如果不是循环添加购买的声音列表;
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult, "声音列表为空");
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            Assert.notNull(trackInfoList, "声音列表为空");
            //获取专辑id 获取专辑对象获取价格
            Long albumId = trackInfoList.get(0).getAlbumId();
            Result<AlbumInfo> albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);
            Assert.notNull(albumInfo, "查询专辑信息失败");
            AlbumInfo albumInfoData = albumInfo.getData();
            Assert.notNull(albumInfoData, "查询专辑信息失败");
            //获取单集声音价格
            BigDecimal price = albumInfoData.getPrice();
            //计算原始金额实际金额 分为单集和多集
            originalAmount = tradeVo.getTrackCount() == 0 ? price : price.multiply(new BigDecimal(tradeVo.getTrackCount()));
            //计算实际金额
            orderAmount = originalAmount;
            //订单明细表 遍历
            for (TrackInfo trackInfo : trackInfoList) {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(price);
                orderDetailVoList.add(orderDetailVo);
            }

        } else {
            //vip会员
            Long vipServiceConfigId = tradeVo.getItemId();

            //获取会员服务配置信息
            Result<VipServiceConfig> serviceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(vipServiceConfigId);
            Assert.notNull(serviceConfigResult, "查询会员服务配置信息失败");
            VipServiceConfig vipServiceConfig = serviceConfigResult.getData();
            Assert.notNull(vipServiceConfig, "查询会员服务配置信息失败");

            //赋值
            //原价
            originalAmount = vipServiceConfig.getPrice();
            //减免价格
            derateAmount = originalAmount.subtract(vipServiceConfig.getDiscountPrice());
            //实际价格
            orderAmount = vipServiceConfig.getDiscountPrice();
            //订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(vipServiceConfig.getId());
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVoList.add(orderDetailVo);
            //减免明细表
            if (derateAmount.compareTo(new BigDecimal("0.00")) == 1) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("VIP打折");
                orderDerateVoList.add(orderDerateVo);
            }
        }


        //赋值
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        //定义一个key
        String orderKey = "user:trade:" + userId;
//        防止重发提交订单

        this.redisTemplate.opsForValue().set(orderKey, tradeNo, 5, TimeUnit.MINUTES);
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        //签名->做数据效验(防止用户通过某种手段篡改订单)签名数据要和订单数据一致,后台根据一样的条件验签,如果不一样说明数据被篡改
        Map map = JSONObject.parseObject(JSONObject.toJSONString(orderInfoVo), Map.class);
        //getSign方法有关系!除去sign 属性数据,将其他数据按照字典顺序进行排列,并将所有属性值使用|进行拼接!在拼接盐(固定字符串),最后将这个字符串进行MD5加密
        String sign = SignHelper.getSign(map);
        orderInfoVo.setSign(sign);
        //返回数据
        return orderInfoVo;
    }

    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //1.效验签名
        Map map = JSONObject.parseObject(JSONObject.toJSONString(orderInfoVo), Map.class);
        map.put("payWay", "");
        SignHelper.checkSign(map);
        //2.效验流水号 Redis+lua 脚本
        //获取页面流水号
        String tradeNo = orderInfoVo.getTradeNo();
        //利用lua脚本进行判断
        //  定义lua 脚本
        String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        //  创建一个 DefaultRedisScript 对象
        DefaultRedisScript defaultRedisScript = new DefaultRedisScript();
        defaultRedisScript.setScriptText(scriptText);
        defaultRedisScript.setResultType(Long.class);
        //定义缓存的key
        String orderKey = "user:trade:" + userId;
        //判断当前流水号是否一致
        Long count = (Long) redisTemplate.execute(defaultRedisScript, Arrays.asList(orderKey), tradeNo);
        //判断影响的行数
        if (count == 0) {
            //如果没有删除成功,则抛出异常,证明是重复提交订单
            throw new GuiguException(ResultCodeEnum.REPEAT_SUBMIT);
        }
        //生成订单编号
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        //3.判断支付类型
        if (!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            //线上支付
            //1.保存支付信息order_derate order_detail order_info
            this.saveOrderInfo(userId, orderNo, orderInfoVo);
            //2.发送延迟消息 订单在规定时间内未支付,取消订单
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER, MqConst.ROUTING_CANCEL_ORDER, orderNo, MqConst.CANCEL_ORDER_DELAY_TIME);
        } else {
            //余额支付
            //检查用户余额是否足够 锁定金额 远程调用
            //创建一个对象 承载 需要购买的订单号 用户id 锁定金额 锁定内容
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            //记录订单明细的商品名称
            accountDeductVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
            //检查与锁定用户金额
            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
            if (200 != result.getCode()) {
                throw new GuiguException(result.getCode(), result.getMessage());
            }
            //2.保存订单信息order_derate order_detail order_info
            this.saveOrderInfo(userId, orderNo, orderInfoVo);
            //修改订单状态
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            //根据订单编号进行修改
            //this.orderInfoMapper.update(orderInfo, new QueryWrapper<OrderInfo>().eq("orderno", orderNo));
            this.orderInfoMapper.update(orderInfo, new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
            //3.保存交易信息
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            //赋值
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            userPaidRecordVo.setOrderNo(orderNo);
            //获取对应的id
            userPaidRecordVo.setItemIdList(orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList()));
            //远程调用 保存交易记录
            Result Transactionhistory = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
            if (200 != Transactionhistory.getCode()) {
                throw new GuiguException(211, "新增购买记录异常");
            }
        }
        //订单编号
        return orderNo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrderInfo(Long userId, String orderNo, OrderInfoVo orderInfoVo) {
        //保存3张表order_derate订单减免表 order_detail订单明细 order_info订单信息
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        //保存订单信息
        orderInfoMapper.insert(orderInfo);
        //保存订单明细
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (!CollectionUtils.isEmpty(orderDetailVoList))
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                //保存订单明细数据
                orderDetailMapper.insert(orderDetail);
            }
        //保存订单减免信息
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)) {
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                //保存订单减免数据
                orderDerateMapper.insert(orderDerate);
            }

        }
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        //  设置支付方式名称
        orderInfo.setPayWayName(SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay()) ? "余额" : "在线");
        return orderInfo;
    }

    @Override
    public IPage<OrderInfo> findUserPage(Page<OrderInfo> page, String orderStatus, Long userId) {
        //查询订单列表(订单表与订单明细表)
        IPage<OrderInfo> iPage = orderInfoMapper.selectUserPage(page, orderStatus, userId);
        iPage.getRecords().forEach(orderInfo -> {
            orderInfo.setOrderStatusName(SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus()) ? "未支付" :
                    SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus()) ? "已支付" : "已取消");
            orderInfo.setPayWayName(SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay()) ? "余额" : "在线");
        });
        return iPage;
    }
}
